package com.chiwen.common.utils.wechat;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chiwen.common.utils.StringUtils;
import com.chiwen.common.utils.http.HttpUtils;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Component
public class WechatUtil {
    private static final Logger log = LoggerFactory.getLogger(WechatUtil.class);

    @Value("${chiwen.wechat.appid}")
    private String appid;

    @Value("${chiwen.wechat.secret}")
    private String secret;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 获取openId
     */
    private final static String JSCODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";

    /**
     * 获取openId
     * get 请求
     * demo:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
     */
    private final static String GET_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

    /**
     * 获取无限小程序码
     * get 请求
     * demo:https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
     */
    private final static String GETWXACODEUNLIMIT_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit";

    private final static String GETWXACODE_URL = "https://api.weixin.qq.com/wxa/getwxacode";

    /**
     * 图片合法检测
     */
    private final static String IMG_SEC_CHECK = "https://api.weixin.qq.com/wxa/img_sec_check";

    /**
     * 图片合法检测
     * https://api.weixin.qq.com/wxa/msg_sec_check?access_token=ACCESS_TOKEN
     */
    private final static String MSG_SEC_CHECK = "https://api.weixin.qq.com/wxa/msg_sec_check";

    /**
     * 一次性订阅消息
     */
    private final static String SUBSCRIBE_SEND = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send";

    // 聚会发布资料审核通知，包括，群或聚会
    public final static String TEMPLATE_AUDIT_NOTICE = "C3-jWPTnDExjl6mW02LyOmxQ37AvqwbMFuZPu75w_xU";
    // 开始通知
    public final static String TEMPLATE_ACT_START_NOTICE = "cSAgJ-VQzmZ0IrGWvniigQRvbD9PTSVtMeSj0yckZPU";
    // 新人加入通知
    public final static String TEMPLATE_NEW_JOIN_NOTICE = "0D0qpfwNbgXyWG6cLitwnAzoLhs35V-M-DZCoouLSD4";
    // 加入审核结果提示,包括，群或聚会
    public final static String TEMPLATE_JOIN_RESULT_NOTICE = "klMmSikUvV2McCVdQ1sNg3nr6DwkIS9PrYFsLnTxRzk";

    // 认证审核通知，如头像审核
    public final static String TEMPLATE_AUTHENTICATION_NOTICE = "7UdsAepF9TzW29iqqyw2OvSORCG2wwcvkBlE9XRkouw";
    // 新消息提醒
    public final static String TEMPLATE_NEW_MSG_NOTICE = "3G0dYC7hFED7lvqGzBL2jrSAXOnQzTw0Ha31UnhzmDQ";

    // 二维码过期提醒
    public final static String TEMPLATE_QRCODE_EXPIRE_NOTICE = "G-vqYe0hE6bgFWaKO_RlQCemMy5jH2i5BrCBfpUJn3E";

    /**
     * 获取openId
     */
    public String getOpenId(String code) {
        String openId = "";
        log.info("入参:【{}】", code);
        try {
            String resp = HttpUtils.sendGet(JSCODE2SESSION_URL, "appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code");
            log.info("接口返回:【{}】", resp);
            JSONObject json = JSON.parseObject(resp);
            // 例子{"session_key":"XfE88MyzGg+UjQ0GhifQcA==","openid":"obT1o5G5Z3nzpZzf8tdAgIvY0QmU"}
            // 错误 {"errcode":40125,"errmsg":"invalid appsecret, view more at http:\/\/t.cn\/RAEkdVq, hints: [ req_id: pKnAO6yFe-xJEs3 ]"}
            if (json.containsKey("openid")) {
                openId = json.getString("openid");
            }
        } catch (Exception e) {
            log.error("异常:{}", e);
            return openId;
        }
        return openId;
    }

    /**
     * wechat access_token
     */
    public static final String WECHAT_TOKEN = "wechat_token";
    /**
     * 获取token
     */
    public String getToken() {
        String token = redisUtils.get(WECHAT_TOKEN);
        if (StringUtils.isBlank(token)) {
            token = getTokenByHttp();
            // 保存时长是100分钟，微信token有效期2小时
            redisUtils.set(WECHAT_TOKEN, token, 100 * 60);
            return token;
        }
        return token;
    }

    /**
     * 获取token
     */
    public String getTokenByHttp() {
        String token = "";
        try {
            String resp = HttpUtils.sendGet(GET_TOKEN_URL, "grant_type=client_credential&appid=" + appid + "&secret=" + secret);
            log.info("接口返回:【{}】", resp);
            JSONObject json = JSON.parseObject(resp);
            if (json.containsKey("access_token")) {
                token = json.getString("access_token");
            } else {
                log.error("获取access_token失败:{}", json.toJSONString());
            }
        } catch (Exception e) {
            log.error("异常:{}", e);
            return token;
        }
        return token;
    }

    /**
     * 获取getwxacodeunlimit
     */
/*    public String getwxacodeunlimit(String accessToken, String scene, String page, String width) {
        if (StringUtils.isBlank(accessToken)) {
            log.info("accessToken为空:【{}】", accessToken);
            return null;
        }
        String token = "";
        try {
            Map<String, String> data = new HashMap<String, String>();
            if (StringUtils.isBlank(scene)) {
                data.put("scene", scene);
            }
            if (StringUtils.isBlank(page)) {
                data.put("page", page);
            }
            if (StringUtils.isBlank(width)) {
                data.put("width", width);
            }
            HttpResponse response = HttpUtilsCustom.doPost(GETWXACODEUNLIMIT_URL, "access_token=" + accessToken, "POST", new HashMap<String, String>(), new HashMap<String, String>(), data);
            String resp = EntityUtils.toString(response.getEntity());

            log.info("接口返回:【{}】", resp);
            JSONObject json = JSON.parseObject(resp);
            if (json.containsKey("errcode")) {
                log.error("获取getwxacodeunlimit失败:{}", json.toJSONString());
            } else {
                // 成功
                System.out.println(json.toString());
            }
        } catch (Exception e) {
            log.error("异常:{}", e);
            return token;
        }
        return token;
    }*/

    /**
     * 获取微信小程序码图片
     * @param sceneStr
     * @param page
     * @param isHyaline
     * @param accessToken
     * @param width
     * @return
     */
    public String getMiniQrcodeNoLimit(String sceneStr, String page, boolean isHyaline, String accessToken, Integer width) {

        RestTemplate rest = new RestTemplate();
        InputStream inputStream = null;
//        OutputStream outputStream = null;
        try {
            String url = GETWXACODEUNLIMIT_URL+"?access_token=" + accessToken;
            Map<String, Object> param = new HashMap<>();
            param.put("scene", sceneStr);
            if (page != null) {
                param.put("page", page);
            }
            if (width != null) {
                param.put("width", width);
            }
            param.put("auto_color", false);
            Map<String, Object> line_color = new HashMap<>();
            line_color.put("r", 0);
            line_color.put("g", 0);
            line_color.put("b", 0);
            param.put("line_color", line_color);
            param.put("is_hyaline", isHyaline);
            log.info("调用生成微信URL接口传参:" + param);
            MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
            HttpEntity requestEntity = new HttpEntity(param, headers);
            ResponseEntity<byte[]> entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]);
            log.info("小程序码URL接口返回结果:" + entity.getBody());
            byte[] result = entity.getBody();
//            log.info(Base64.encodeBase64String(result));
            inputStream = new ByteArrayInputStream(result);

            String fileName = "未配置图片上传路径";
//                    FileUploadUtils.uploadToOss("miniCode", inputStream);
            System.out.println(fileName);
            return fileName;
        } catch (Exception e) {
            log.error("调用小程序码URL接口异常", e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            /*if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }*/
        }
        return null;
    }

    /**
     * 获取微信小程序码图片,每天10万限制
     *
     * @param sceneStr
     * @param page
     * @param isHyaline
     * @param accessToken
     * @param width
     * @return
     */
    public String getMiniQrcode(String sceneStr, String page, boolean isHyaline, String accessToken, Integer width) {
//        if (Global.isDemoEnabled()) {
//            return "main.jpg";
//        }
        RestTemplate rest = new RestTemplate();
        InputStream inputStream = null;
//        OutputStream outputStream = null;
        try {
            String url = GETWXACODE_URL+"?access_token=" + accessToken;
            Map<String, Object> param = new HashMap<>();
            param.put("path", page+"?from=share&"+sceneStr);
            if (width != null) {
                param.put("width", width);
            }
            param.put("auto_color", false);
            Map<String, Object> line_color = new HashMap<>();
            line_color.put("r", 0);
            line_color.put("g", 0);
            line_color.put("b", 0);
            param.put("line_color", line_color);
            param.put("is_hyaline", isHyaline);
            log.info("调用生成微信URL接口传参:" + param);
            MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
            HttpEntity requestEntity = new HttpEntity(param, headers);
            ResponseEntity<byte[]> entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]);
            log.info("小程序码URL接口返回结果:" + entity.getBody());
            byte[] result = entity.getBody();
//            log.info(Base64.encodeBase64String(result));
            inputStream = new ByteArrayInputStream(result);

            String fileName = "未配置图片上传路径2";
//                    FileUploadUtils.uploadToOss("miniCode", inputStream);
            System.out.println(fileName);
            return fileName;
        } catch (Exception e) {
            log.error("调用小程序码URL接口异常", e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            /*if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }*/
        }
        return null;
    }

    /**
     * 检测图形是否合法
     *
     * @param file
     * @return
     */
    public boolean imgSecCheck(MultipartFile file) throws Exception {
//        if (Global.isDemoEnabled()) {
//            return true;
//        }
        OutputStream os = null;
        // 判断文件大小，如超过1024kb ,则压缩
        byte[] bytes = commpressPicCycle(file.getBytes(), 1024L, 0.6);

        String token = getToken();
        String url = IMG_SEC_CHECK + "?access_token=" + token;
        String result =  "未配置图片上传路径";

//                    HttpUtils.uploadFile(url, bytes);
        JSONObject json = JSON.parseObject(result);
        if (json.containsKey("errcode")) {
            int errcode = json.getIntValue("errcode");
            if (errcode == 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检测文本
     * @param textConetnt
     * @return
     */
    public boolean msgSecCheck(String textConetnt) {
//        if (Global.isDemoEnabled()) {
//            return true;
//        }
        try {
            CloseableHttpClient httpclient = HttpClients.createDefault();
            CloseableHttpResponse response = null;
            String accessToken = getToken();
            HttpPost request = new HttpPost(MSG_SEC_CHECK+"?access_token=" + accessToken);
            request.addHeader("Content-Type", "application/json;charset=UTF-8");

            Map<String, String> paramMap = new HashMap<String, String>();
            paramMap.put("content", textConetnt);
            request.setEntity(new StringEntity(JSONObject.toJSONString(paramMap), ContentType.create("application/json", "utf-8")));

            response = httpclient.execute(request);
            org.apache.http.HttpEntity httpEntity = response.getEntity();
            String result = EntityUtils.toString(httpEntity, "UTF-8");// 转成string
            JSONObject jso = JSONObject.parseObject(result);

            Object errcode = jso.get("errcode");
            int errCode = (int) errcode;
            if (errCode == 0) {
                return true;
            } else if (errCode == 87014) {
                log.info("内容违规-----------" + textConetnt);
                return false;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.info("----------------调用腾讯内容过滤系统出错------------------");
            return true;
        }
    }

    /**
     *
     * @param bytes 原图片字节数组
     * @param desFileSize 指定图片大小,单位 kb
     * @param accuracy 精度,递归压缩的比率,建议小于0.9
     * @return
     */
    public static byte[] commpressPicCycle(byte[] bytes, long desFileSize, double accuracy) throws IOException{
        // 获取目标图片
//        File imgFile = new File(desPath);
//        long fileSize = imgFile.length();
        long fileSize = bytes.length;
        log.info("=====fileSize======== "+fileSize);
        // 判断图片大小是否小于指定图片大小
        if(fileSize <= desFileSize * 1024){
            return bytes;
        }
        //计算宽高
        BufferedImage bim = ImageIO.read(new ByteArrayInputStream(bytes));
        int imgWidth = bim.getWidth();
        log.info(imgWidth+"====imgWidth=====");
        int imgHeight = bim.getHeight();
        int desWidth = new BigDecimal(imgWidth).multiply( new BigDecimal(accuracy)).intValue();
        log.info(desWidth+"====desWidth=====");
        int desHeight = new BigDecimal(imgHeight).multiply( new BigDecimal(accuracy)).intValue();
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); //字节输出流（写入到内存）
        Thumbnails.of(new ByteArrayInputStream(bytes)).size(desWidth, desHeight).outputQuality(accuracy).toOutputStream(baos);
        //如果不满足要求,递归直至满足要求
        return commpressPicCycle(baos.toByteArray(), desFileSize, accuracy);
    }

    /**
     * 推送底层
     *
     * @param touser
     * @param templateId
     * @param page
     * @param jsonData
     * @return
     */
    public boolean pushMsgCommon(String touser, String templateId, String page, JSONObject jsonData) {
        try {
            JSONObject json = new JSONObject();
            json.put("touser", touser);
            json.put("template_id", templateId);
            // 跳转地址，没有则不填，如果有：必须是小程序内页面地址，支持带参数
            json.put("page", page);
            json.put("data", jsonData);

            // 请求url
            String url = SUBSCRIBE_SEND + "?access_token=" + getToken();
            // 发起请求
            String response = HttpUtil.post(url, json.toJSONString());
            log.info("请求参数:{},返回值:{}", json.toJSONString(), response);
            JSONObject parse = JSONObject.parseObject(response);
            if (parse.getIntValue("errcode") == 0) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            log.error("异常:", e);
            return false;
        }
    }

    /**
     * 初始化json数据
     *
     * @param info
     * @return
     * @date 2019年11月25日下午5:05:56
     */
    public JSONObject initJson(String info) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("value", info);
//		jsonObject.put("color","#173177");
        return jsonObject;
    }


}

